//
//  UIViewControllerEx.swift
//  Risac
//
//  Created by remy on 2018/3/19.
//

import UIKit

extension UIViewController {
    // http://stackoverflow.com/questions/23620276/check-if-view-controller-is-presented-modally-or-pushed-on-a-navigation-stack
    public var isModal: Bool {
        if presentingViewController != nil {
            return true
        }
        if let nc = navigationController?.presentingViewController?.presentedViewController, nc === navigationController {
            return true
        }
        if tabBarController?.presentingViewController is UITabBarController {
            return true
        }
        return false
    }
    
    public func modal<T: UINavigationController>(_ vc: UIViewController,
                                                 with: T.Type? = nil,
                                                 animated: Bool = true,
                                                 config: ((UIViewController) -> Void)? = nil,
                                                 completion: (() -> Void)? = nil) {
        var controller: UIViewController = vc
        if let nc = with {
            controller = nc.init(rootViewController: self)
        } else {
            if vc.popoverPresentationController != nil {
                return self.modalPopover(vc, animated: animated, completion: completion)
            }
        }
        config?(controller)
        present(controller, animated: animated, completion: completion)
    }
    
    public func modalNC(_ vc: UIViewController,
                        with: UINavigationController.Type = UINavigationController.self,
                        animated: Bool = true,
                        completion: (() -> Void)? = nil) {
        self.modal(vc, with: with, animated: animated, config: {
            $0.modalPresentationStyle = .fullScreen
        }, completion: completion)
    }
    
    public func modalTransparentNC(_ vc: UIViewController,
                                   with: UINavigationController.Type = UINavigationController.self,
                                   animated: Bool = true,
                                   completion: (() -> Void)? = nil) {
        self.modal(vc, with: with, animated: animated, config: {
            $0.modalPresentationStyle = .custom
            $0.modalPresentationCapturesStatusBarAppearance = true
        }, completion: completion)
    }
    
    public func modalPopover(_ vc: UIViewController,
                             sourceView: UIView? = nil,
                             sourceRect: CGRect? = nil,
                             animated: Bool = true,
                             config: ((UIPopoverPresentationController) -> Void)? = nil,
                             completion: (() -> Void)? = nil) {
        guard let pop = vc.popoverPresentationController else { return }
        if let view = sourceView {
            pop.sourceView = view
            pop.sourceRect = sourceRect ?? view.bounds
        } else {
            guard let window = UIApplication.shared.keyWindow else { return }
            pop.sourceView = window
            pop.sourceRect = CGRect(x: window.bounds.midX, y: window.bounds.maxY, width: 0.0, height: 0.0)
        }
        config?(pop)
        present(vc, animated: animated, completion: completion)
    }
}

extension UIViewController {
    private func run(_ block: (UINavigationController) -> Void, _ completion: ((UINavigationController) -> Void)?) {
        guard let nc = navigationController else { return }
        if let completion = completion {
            // MARK: pushVC会导致生命周期(viewDidLoad等)提前执行
            CATransaction.begin()
            CATransaction.setCompletionBlock { completion(nc) }
            block(nc)
            CATransaction.commit()
        } else {
            block(nc)
        }
    }
    
    public func pushVC(_ vc: UIViewController,
                       animated: Bool = true,
                       completion: ((UINavigationController) -> Void)? = nil) {
        run({ $0.pushViewController(vc, animated: animated) }, completion)
    }
    
    public func popVC(animated: Bool = true, completion: ((UINavigationController) -> Void)? = nil) {
        run({ $0.popViewController(animated: animated) }, completion)
    }
    
    public func popToRootVC(animated: Bool = true, completion: ((UINavigationController) -> Void)? = nil) {
        run({ $0.popToRootViewController(animated: animated) }, completion)
    }
    
    public func popToVC(_ vc: UIViewController,
                        animated: Bool = true,
                        completion: ((UINavigationController) -> Void)? = nil) {
        guard navigationController?.viewControllers.contains(vc) ?? false else { return }
        run({ $0.popToViewController(vc, animated: animated) }, completion)
    }
    
    public func popToVC(_ count: Int,
                        animated: Bool = true,
                        completion: ((UINavigationController, Bool) -> Void)? = nil) {
        guard let nc = navigationController else { return }
        guard let vc = nc.viewControllers[safe: nc.viewControllers.count - count - 1] else {
            completion?(nc, false)
            return
        }
        run({ $0.popToViewController(vc, animated: animated) }) { completion?($0, true) }
    }
    
    public func popAndPush(_ vc: UIViewController,
                           animated: Bool = true,
                           completion: ((UINavigationController) -> Void)? = nil) {
        guard let nc = navigationController else { return }
        if nc.viewControllers.count > 1 {
            nc.popViewController(animated: false)
        }
        run({ $0.pushViewController(vc, animated: animated) }, completion)
    }
    
    public func popToVC(_ cls: AnyClass,
                        animated: Bool = true,
                        completion: ((UINavigationController, Bool) -> Void)? = nil) {
        guard let nc = navigationController else { return }
        guard nc.viewControllers.count > 1 else { return }
        let past = nc.viewControllers[0..<nc.viewControllers.count - 1].reversed()
        for vc in past {
            guard vc.isKind(of: cls) else { continue }
            return run({ $0.popToViewController(vc, animated: animated) }) { completion?($0, true) }
        }
        completion?(nc, false)
    }
}

extension UIViewController {
    public func addChildVC(_ vc: UIViewController, toView: UIView? = nil) {
        guard let toView = toView ?? self.view else { return }
        self.addChild(vc)
        toView.addSubview(vc.view)
        vc.didMove(toParent: self)
    }
    
    public func removeFromParantVC() {
        self.willMove(toParent: nil)
        self.view.removeFromSuperview()
        self.removeFromParent()
    }
}
